package com.yeskery.nut.scan.controller;

import com.yeskery.nut.application.NutApplication;
import com.yeskery.nut.bean.*;
import com.yeskery.nut.bind.*;
import com.yeskery.nut.bind.validator.BindingResult;
import com.yeskery.nut.bind.validator.CustomMethodParamValidatorHandler;
import com.yeskery.nut.bind.validator.DataBindValidException;
import com.yeskery.nut.bind.validator.ErrorValidResult;
import com.yeskery.nut.core.*;
import com.yeskery.nut.extend.auth.CrossConfiguration;
import com.yeskery.nut.http.HttpMediaTypeNotSupportException;
import com.yeskery.nut.http.HttpNotAcceptableException;
import com.yeskery.nut.http.HttpRequestHeaderNotMatchException;
import com.yeskery.nut.http.HttpRequestParamNotMatchException;
import com.yeskery.nut.plugin.BindContext;
import com.yeskery.nut.util.CrossUtils;
import com.yeskery.nut.util.ReflectUtils;
import com.yeskery.nut.util.StringUtils;
import com.yeskery.nut.view.ModelAndView;
import com.yeskery.nut.view.ViewHandler;

import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Parameter;
import java.util.*;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * 基于注解注册的controller动态代理处理对象
 * @author sprout
 * 2022-06-10 17:54
 */
public class AnnotationControllerInvocationHandler extends AbstractControllerInvocationHandler {

    /** 日志对象 */
    private static final Logger logger = Logger.getLogger(AnnotationControllerInvocationHandler.class.getName());

    /** 原始Controller类名称 */
    public static final String ORIGINAL_CONTROLLER_CLASS_NAME = "ORIGINAL_CONTROLLER_CLASS_NAME";

    /** 重定向前缀 */
    private static final String REDIRECT_PREFIX = "redirect:";

    /** 跳转 */
    private static final String FORWARD = "forward";

    /** 跳转方法开始符号 */
    private static final String FORWARD_METHOD_START = "(";

    /** 跳转方法结束符号 */
    private static final String FORWARD_METHOD_END = ")";

    /** 等于 */
    private static final String EQUAL = "=";

    /** 取反 */
    private static final String REVERSE = "!";

    /** 逗号 */
    private static final String COMMA = ",";

    /** 冒号 */
    private static final String COLON = ":";

    /** 跳转前缀 */
    private static final String FORWARD_PREFIX = FORWARD + COLON;

    /** 根路径 */
    private static final String ROOT_PATH = "/";

    /** 请求方法处理map */
    private final Map<com.yeskery.nut.core.Method, AnnotationRequestMethodAttributes> methodHandleMap;

    /** 注解数据绑定处理器 */
    private final AnnotationDataBindHandler annotationDataBindHandler = new AnnotationDataBindHandler();

    /** 应用上下文bean持有对象 */
    private final ApplicationContextBeanHolder applicationContextBeanHolder;

    /** Nut应用对象 */
    private final NutApplication nutApplication;

    /** 响应体处理器集合 */
    private List<ResponseBodyHandler> responseBodyHandlers;

    /** Http响应体处理器集合 */
    private List<HttpResponseBodyHandler> httpResponseBodyHandlers;

    /** 自定义方法参数处理器map */
    private Map<Class<?>, CustomMethodParamBindHandler<?>> customMethodParamHandlerMap;

    /** 自定义参数验证处理器集合 */
    private Set<CustomMethodParamValidatorHandler> customMethodParamValidatorHandlers;

    /**
     * 构建controller动态代理处理对象
     * @param nutApplication Nut应用对象
     * @param target 目标对象
     * @param methodHandleMap 请求方法处理map
     */
    public AnnotationControllerInvocationHandler(NutApplication nutApplication, Object target,
                                                 Map<com.yeskery.nut.core.Method, AnnotationRequestMethodAttributes> methodHandleMap) {
        super(target);
        this.nutApplication = nutApplication;
        this.methodHandleMap = methodHandleMap;
        this.applicationContextBeanHolder = new ApplicationContextBeanHolder(nutApplication.getApplicationContext());
    }

    /**
     * 获取注解请求方法属性
     * @return 注解请求方法属性
     */
    public AnnotationRequestMethodAttributes getAnnotationRequestMethodAttributes() {
        if (methodHandleMap.isEmpty()) {
            return null;
        }
        return methodHandleMap.values().stream().findFirst().orElse(null);
    }

    /**
     * 获取请求方法处理map
     * @return 请求方法处理map
     */
    public Map<com.yeskery.nut.core.Method, AnnotationRequestMethodAttributes> getAnnotationMethodHandleMap() {
        return methodHandleMap;
    }

    @Override
    protected void doRequest(Request request, Response response, Execution execution) {
        AnnotationRequestMethodAttributes attributes = methodHandleMap.get(request.getMethod());
        if (attributes == null) {
            attributes = methodHandleMap.get(Method.ALL);
        }
        if (attributes == null) {
            throw new ResponseNutException(ResponseCode.NOT_FOUND.getDescription(), ResponseCode.NOT_FOUND);
        }
        verifyWebRequestFilterMetadata(request, attributes);
        RequestApplicationContext.putResource(ORIGINAL_CONTROLLER_CLASS_NAME, attributes.getType());
        boolean responseBody = attributes.isResponseBody();

        java.lang.reflect.Method method = attributes.getMethod();
        Object[] params = paddingMethodParameters(attributes, request, response, execution);

        Class<?> type = attributes.getType();

        WebApplicationContext webApplicationContext = (WebApplicationContext) nutApplication.getWebApplicationContext();
        Object target = getControllerBeanByApplication(webApplicationContext, type);
        try {
            setWebRequestHolder(webApplicationContext, request);
            Collection<CrossConfiguration> crossConfigurations = attributes.getCrossConfigurations();
            if (!crossConfigurations.isEmpty()) {
                Optional<CrossConfiguration> optional = CrossUtils.getRequestCross(crossConfigurations, request, response, false);
                if (!optional.isPresent()) {
                    throw new ResponseNutException(ResponseCode.FORBIDDEN);
                }
            }
            Object result = method.invoke(target, params);
            if (result != null) {
                response.setCode(attributes.getResponseCode());
                if (responseBody) {
                    boolean flag = false;
                    for (ResponseBodyHandler handler : getResponseBodyHandlers()) {
                        if (handler.support(method, result)) {
                            handler.handle(result, request, response);
                            flag = handler.outputResponse();
                            if (flag) {
                                break;
                            }
                        }
                    }
                    if (!flag) {
                        HttpResponseBodyMetadata responseBodyMetadata = getHttpResponseBodyMetadata(request, response, execution, result, attributes);
                        boolean handled = false;
                        for (HttpResponseBodyHandler handler : getHttpResponseBodyHandlers()) {
                            if (handler.support(responseBodyMetadata)) {
                                handler.handle(responseBodyMetadata);
                                handled = true;
                                break;
                            }
                        }
                        if (!handled) {
                            throw new HttpMediaTypeNotSupportException("Produce Media Type[" + String.join(", ", attributes.getProduces()) + "] Not Support.");
                        }
                    }
                } else {
                    if (result instanceof ModelAndView) {
                        execution.getViewHandler().handle((ModelAndView) result, request, response);
                    } else if (result instanceof String) {
                        String path = (String) result;
                        if (path.startsWith(REDIRECT_PREFIX)) {
                            path = path.substring(REDIRECT_PREFIX.length());
                            response.sendRedirect(StringUtils.isEmpty(path) ? ROOT_PATH : path);
                        } else if (path.startsWith(FORWARD_PREFIX)) {
                            path = path.substring(FORWARD_PREFIX.length());
                            if (StringUtils.isEmpty(path)) {
                                response.sendRedirect(ROOT_PATH);
                            } else {
                                execution.getForward().forward(request, response, execution, path);
                            }
                        } else if (path.startsWith(FORWARD + FORWARD_METHOD_START) && path.contains(FORWARD_METHOD_END + COLON)) {
                            path = path.substring(FORWARD.length());
                            if (StringUtils.isEmpty(path)) {
                                response.sendRedirect(ROOT_PATH);
                                return;
                            }
                            int startIndex = path.indexOf(FORWARD_METHOD_START), endIndex;
                            if (startIndex == -1 || (endIndex = path.indexOf(FORWARD_METHOD_END)) == -1) {
                                response.sendRedirect(ROOT_PATH);
                                return;
                            }
                            String forwardMethod = path.substring(startIndex, endIndex), forwardUri;
                            if (StringUtils.isEmpty(forwardMethod) || StringUtils.isEmpty(forwardUri = path.substring(endIndex + 1))) {
                                response.sendRedirect(ROOT_PATH);
                                return;
                            }
                            execution.getForward().forward(request, response, execution, forwardUri, Method.valueOf(forwardMethod.toUpperCase()));
                        } else {
                            ModelAndView modelAndView = new ModelAndView();
                            modelAndView.setView(path);
                            execution.getViewHandler().handle(modelAndView, request, response);
                        }
                    } else {
                        throw new NutException("View Resolver Not Support Return Type[" + result.getClass().getName() + "].");
                    }
                }
            }
        } catch (Exception e) {
            throw new ProxyObjectInvokeException("Target Method Execute Fail.", e);
        } finally {
            removeWebRequestHolder(webApplicationContext);
        }
    }

    @Override
    protected boolean isTargetRequest(Request request, com.yeskery.nut.core.Method method) {
        Set<com.yeskery.nut.core.Method> methods = methodHandleMap.keySet();
        return methods.contains(com.yeskery.nut.core.Method.ALL) || methods.contains(method);
    }

    /**
     * 填充方法参数
     * @param attributes 注解请求方法属性
     * @param request 请求对象
     * @param response 响应对象
     * @param execution 执行接口
     * @return 填充后的方法参数数组
     */
    private Object[] paddingMethodParameters(AnnotationRequestMethodAttributes attributes, Request request,
                                         Response response, Execution execution) {
        FitValueHelper fitValueHelper = FitValueHelper.getInstance();
        java.lang.reflect.Method method = attributes.getMethod();
        Map<Integer, List<Annotation>> annotationIndexMap = attributes.getAnnotationIndexMap();
        Parameter[] parameters = method.getParameters();
        Object[] params = new Object[method.getParameters().length];
        BindingResult bindingResult = null;
        boolean isValid = false;
        boolean isCustomDeal = false;
        for (int i = 0; i < parameters.length; i++) {
            Parameter parameter = parameters[i];
            if (annotationIndexMap.containsKey(i)) {
                for (Annotation annotation : annotationIndexMap.get(i)) {
                    MethodParamHandler handler = annotationDataBindHandler.handle(annotation);
                    if (handler == null) {
                        continue;
                    }
                    AnnotationBindObject annotationBindObject = handler.handle(attributes, annotation, parameter, request, execution);
                    if (annotationBindObject.isEmpty()) {
                        if (annotationBindObject.isRequired()) {
                            String message = "Annotation Class [" + annotationBindObject.getType().getName() + "] ";
                            if (annotationBindObject.getValue() != null) {
                                String name = annotationBindObject.getValue().trim().isEmpty()
                                        ? parameter.getName() : annotationBindObject.getValue();
                                message += "Parameter [" + name + "] ";
                            }
                            throw new DataBindException(message + "Are Required.");
                        } else {
                            params[i] = annotationBindObject.getData();
                            break;
                        }
                    } else {
                        params[i] = annotationBindObject.getData();
                        break;
                    }
                }
            } else {
                Class<?> type = parameter.getType();
                if (type.isAssignableFrom(Request.class)) {
                    params[i] = request;
                } else if (type.isAssignableFrom(Session.class)) {
                    params[i] = request.getSession();
                } else if (type.isAssignableFrom(Response.class)) {
                    params[i] = response;
                } else if (type.isAssignableFrom(Execution.class)) {
                    params[i] = execution;
                } else if (type.isAssignableFrom(Forward.class)) {
                    params[i] = execution.getForward();
                } else if (type.isAssignableFrom(BindContext.class)) {
                    params[i] = execution.getBindContext();
                } else if (type.isAssignableFrom(ViewHandler.class)) {
                    params[i] = execution.getViewHandler();
                } else if (type.isAssignableFrom(Model.class)) {
                    params[i] = Model.DEFAULT_MODEL;
                } else if (type.isAssignableFrom(MultipartFile.class)) {
                    String name = parameter.getName();
                    params[i] = request.getFile(name);
                } else if (type.equals(BindingResult.class)) {
                    if (bindingResult == null) {
                        throw new DataBindException("Need To Use @Valid Before Using BindingResult.");
                    }
                    params[i] = bindingResult;
                    isCustomDeal = true;
                } else {
                    params[i] = getCustomMethodParameter(parameter, fitValueHelper, request, response, execution);
                }
            }

            if (!isValid && params[i] != null) {
                for (CustomMethodParamValidatorHandler handler : getCustomMethodParamValidatorHandlers()) {
                    if (handler.isSupport(parameter)) {
                        Set<ErrorValidResult> validResults = handler.handle(params[i]);
                        bindingResult = new BindingResult(validResults);
                        isValid = true;
                    }
                }
            }
        }

        if (isValid && !isCustomDeal && bindingResult.hasErrors()) {
            ErrorValidResult errorValidResult = bindingResult.getErrorValidResults().iterator().next();
            throw new DataBindValidException("Field Name [" + errorValidResult.getFieldName()
                    + "] Valid Failure, Cause Reason [" + errorValidResult.getMessage() + "].", bindingResult);
        }
        return params;
    }

    /**
     * 获取自定义方法参数
     * @param parameter 参数对象
     * @param fitValueHelper 合适值帮助类
     * @param request 请求对象
     * @param response 响应对象
     * @param execution 执行接口
     * @return 自定义方法参数
     */
    private Object getCustomMethodParameter(Parameter parameter, FitValueHelper fitValueHelper, Request request,
                                            Response response, Execution execution) {
        Object value;
        Class<?> type = parameter.getType();
        CustomMethodParamBindHandler<?> methodParamBindHandler = getCustomMethodParamBindHandler(type);
        if (methodParamBindHandler == null) {
            String name = parameter.getName();
            if (fitValueHelper.isBasicTypeClass(parameter.getType())) {
                value = FitValueHelper.getInstance().getFitParamValue(name, request.getParameter(name),
                        parameter.getType()).getData();
            } else {
                value = buildRequestParamsObject(parameter, request, fitValueHelper);
            }

        } else {
            value = methodParamBindHandler.handle(parameter, request, execution);
            if (!type.isAssignableFrom(value.getClass())) {
                logger.log(Level.WARNING, "CustomMethodParamBindHandler ["
                        + methodParamBindHandler.getClass().getName() + "], Provide Class ["
                        + value.getClass().getName() + "], But Expect Class [" + type.getName() + "]");
                value = null;
            }
        }

        if (value == null) {
            try {
                value = applicationContextBeanHolder.getHoldBean(parameter);
            } catch (NoSuchBeanException e) {
                logger.logp(Level.WARNING, this.getClass().getName(), "doRequest",
                        "Unable To Obtain Controller Method Parameter Object Type ["
                                + parameter.getType() + "] From Application.", e);
            }
        }
        return value;
    }

    /**
     * 获取自定义方法参数绑定处理器
     * @param clazz 当前参数类型
     * @return 自定义方法参数绑定处理器
     */
    private CustomMethodParamBindHandler<?> getCustomMethodParamBindHandler(Class<?> clazz) {
        return getCustomMethodParamHandlerMap().get(clazz);
    }

    /**
     * 构造请求参数对象
     * @param parameter 参数对象
     * @param request 请求对象
     * @return 请求参数对象
     */
    private Object buildRequestParamsObject(Parameter parameter, Request request, FitValueHelper fitValueHelper) {
        Class<?> clazz = parameter.getType();
        Object instance;
        try {
            Constructor<?> constructor = clazz.getConstructor();
            instance = constructor.newInstance();
        } catch (NoSuchMethodException | InvocationTargetException | InstantiationException | IllegalAccessException e) {
            return null;
        }
        Map<String, String> parameterMap = request.getParameterMap();
        boolean setting = false;
        for (Field field : ReflectUtils.getBeanAllField(clazz)) {
            String name = field.getName();
            if (parameterMap.containsKey(name)) {
                try {
                    ReflectUtils.setObjectFieldValue(instance, field,
                            fitValueHelper.getFitParamValue(name, parameterMap.get(name), field.getType()).getData());
                    if (!setting) {
                        setting = true;
                    }
                } catch (Exception e) {
                    throw new DataBindException("Class [" + clazz.getName() + "] Field [" + name
                            + "] Value [" + parameterMap.get(name) + "] Bind Fail.");
                }
            }
        }
        return instance;
    }

    /**
     * 获取Controller，并且将当前Controller注册到应用上下文
     * @param applicationContext 应用上下文
     * @param clazz 目标对象类型
     * @return 目标对象
     */
    private Object getControllerBeanByApplication(WebApplicationContext applicationContext, Class<?> clazz) {
        try {
            return applicationContext.getBean(clazz);
        } catch (NoSuchBeanException e) {
            // Not Need Deal.
        }
        try {
            applicationContext.registerControllerBean(clazz);
            return applicationContext.getBean(clazz);
        } catch (Exception e) {
            if (e instanceof BeanException) {
                try {
                    return applicationContext.getBean(clazz);
                } catch (Exception e1) {
                    throw new NutException("Class Instance Create Fail.", e);
                }
            } else {
                throw new NutException("Class Instance Create Fail.", e);
            }
        }
    }

    /**
     * 初始化请求持有类
     * @param applicationContext 应用上下文
     * @param request 请求对象
     */
    private void setWebRequestHolder(ApplicationContext applicationContext, Request request) {
        try {
            Request requestBean = applicationContext.getBean(Request.class);
            if ((requestBean instanceof AbstractRequestHolder)) {
                ((AbstractRequestHolder) requestBean).setRequest(request);
            }
            Session session = applicationContext.getBean(Session.class);
            if ((session instanceof AbstractRequestHolder)) {
                ((AbstractRequestHolder) session).setRequest(request);
            }
            ServerContext serverContext = applicationContext.getBean(ServerContext.class);
            if ((serverContext instanceof AbstractRequestHolder)) {
                ((AbstractRequestHolder) serverContext).setRequest(request);
            }
        } catch (NoSuchBeanException e) {
            // Not Need Deal.
        }
    }

    /**
     * 移除请求持有类
     * @param applicationContext 应用上下文
     */
    private void removeWebRequestHolder(ApplicationContext applicationContext) {
        try {
            Request requestBean = applicationContext.getBean(Request.class);
            if ((requestBean instanceof AbstractRequestHolder)) {
                ((AbstractRequestHolder) requestBean).removeRequest();
            }
            Session session = applicationContext.getBean(Session.class);
            if ((session instanceof AbstractRequestHolder)) {
                ((AbstractRequestHolder) session).removeRequest();
            }
            ServerContext serverContext = applicationContext.getBean(ServerContext.class);
            if ((serverContext instanceof AbstractRequestHolder)) {
                ((AbstractRequestHolder) serverContext).removeRequest();
            }
        } catch (NoSuchBeanException e) {
            // Not Need Deal.
        }
    }

    /**
     * 获取响应体处理器集合
     * @return 响应体处理器集合
     */
    private List<ResponseBodyHandler> getResponseBodyHandlers() {
        if (responseBodyHandlers == null) {
            responseBodyHandlers = new ArrayList<>(nutApplication.getNutWebConfigure().getResponseBodyHandlers());
            responseBodyHandlers.sort(Comparator.comparing(Order::getOrder));
        }
        return responseBodyHandlers;
    }

    /**
     * 获取Http响应体处理器集合
     * @return Http响应体处理器集合
     */
    private List<HttpResponseBodyHandler> getHttpResponseBodyHandlers() {
        if (httpResponseBodyHandlers == null) {
            httpResponseBodyHandlers = new ArrayList<>(nutApplication.getNutWebConfigure().getHttpResponseBodyHandlers());
            httpResponseBodyHandlers.sort(Comparator.comparing(Order::getOrder));
        }
        return httpResponseBodyHandlers;
    }

    /**
     * 获取自定义方法参数处理器map
     * @return 自定义方法参数处理器map
     */
    private Map<Class<?>, CustomMethodParamBindHandler<?>> getCustomMethodParamHandlerMap() {
         if (customMethodParamHandlerMap == null) {
             customMethodParamHandlerMap = new HashMap<>(nutApplication.getNutWebConfigure().getMethodParamBindHandlers());
         }
         return customMethodParamHandlerMap;
    }

    /**
     * 获取自定义参数验证处理器集合
     * @return 自定义参数验证处理器集合
     */
    private Set<CustomMethodParamValidatorHandler> getCustomMethodParamValidatorHandlers() {
         if (customMethodParamValidatorHandlers == null) {
             customMethodParamValidatorHandlers = new HashSet<>(nutApplication.getNutWebConfigure().getMethodParamValidatorHandlers());
         }
         return customMethodParamValidatorHandlers;
    }

    /**
     * 获取Http响应体元数据
     * @param request 请求对象
     * @param response 响应对象
     * @param execution 执行器
     * @param result 执行结果
     * @param attributes 注解请求方法属性
     * @return Http响应体元数据
     */
    private HttpResponseBodyMetadata getHttpResponseBodyMetadata(Request request, Response response, Execution execution,
                                                                 Object result, AnnotationRequestMethodAttributes attributes) {
        HttpResponseBodyMetadata httpResponseBodyMetadata = new HttpResponseBodyMetadata();
        httpResponseBodyMetadata.setApplicationContext(nutApplication.getWebApplicationContext());
        httpResponseBodyMetadata.setAttributes(attributes);
        httpResponseBodyMetadata.setBindContext(execution.getBindContext());
        httpResponseBodyMetadata.setResult(result);
        httpResponseBodyMetadata.setRequest(request);
        httpResponseBodyMetadata.setResponse(response);
        return httpResponseBodyMetadata;
    }

    /**
     * 验证请求元数据是否匹配
     * @param request 请求对象
     * @param attributes 注解请求方法属性
     */
    private void verifyWebRequestFilterMetadata(Request request, AnnotationRequestMethodAttributes attributes) {
        // 检查参数是否匹配
        for (String param : attributes.getParams()) {
            if (!StringUtils.isBlank(param)) {
                doVerifyWebRequestParamFilterMetadata(request, param);
            }
        }

        // 检查请求头是否匹配
        for (String header : attributes.getHeaders()) {
            if (!StringUtils.isBlank(header)) {
                doVerifyWebRequestHeaderFilterMetadata(request, header);
            }
        }

        // 检查Content-Type是否匹配
        for (String consume : attributes.getConsumes()) {
            if (!StringUtils.isBlank(consume)) {
                doVerifyWebRequestConsumeFilterMetadata(request, consume);
            }
        }

        // 检查Accept是否匹配
        for (String produce : attributes.getProduces()) {
            if (!StringUtils.isBlank(produce)) {
                doVerifyWebRequestProduceFilterMetadata(request, produce);
            }
        }
    }

    /**
     * 验证请求参数元数据是否匹配
     * @param request 请求对象
     * @param param 参数表达式
     */
    private void doVerifyWebRequestParamFilterMetadata(Request request, String param) {
        boolean passed = true;
        boolean reverse = false;
        if (param.contains(EQUAL)) {
            String[] splits = param.split(EQUAL, 2);
            if (splits.length == 2) {
                String key = splits[0].trim();
                if (key.length() > 1 && key.endsWith(REVERSE)) {
                    key = key.substring(0, key.length() - 1);
                    reverse = true;
                }
                String value = splits[1].trim();
                if (StringUtils.isBlank(value)) {
                    passed = request.getParameterKeys().contains(key);
                } else if (value.contains(COMMA)) {
                    String paramValue = request.getParameter(key);
                    passed = Arrays.asList(value.split(COMMA)).contains(paramValue);
                } else {
                    passed = value.equals(request.getParameter(key));
                }
            }
        } else {
            String key = param;
            if (param.length() > 1 && param.startsWith(REVERSE)) {
                key = key.substring(1);
                reverse = true;
            }
            passed = request.getParameterKeys().contains(key);
        }
        if (reverse) {
            passed = !passed;
        }
        if (!passed) {
            throw new HttpRequestParamNotMatchException("Http Request Param["+ param +"] Not Match.");
        }
    }

    /**
     * 验证请求头元数据是否匹配
     * @param request 请求对象
     * @param header 请求头表达式
     */
    private void doVerifyWebRequestHeaderFilterMetadata(Request request, String header) {
        boolean passed = true;
        boolean reverse = false;
        if (header.contains(EQUAL)) {
            String[] splits = header.split(EQUAL, 2);
            if (splits.length == 2) {
                String key = splits[0].trim();
                if (key.length() > 1 && key.endsWith(REVERSE)) {
                    key = key.substring(0, key.length() - 1);
                    reverse = true;
                }
                String value = splits[1].trim();
                passed = value.equals(request.getHeader(key));
            }
        } else {
            String key = header;
            if (header.length() > 1 && header.startsWith(REVERSE)) {
                key = key.substring(1);
                reverse = true;
            }
            passed = request.getHeaders().containsKey(key);
        }
        if (reverse) {
            passed = !passed;
        }
        if (!passed) {
            throw new HttpRequestHeaderNotMatchException("Http Request Header["+ header +"] Not Match.");
        }
    }

    /**
     * 验证Content-Type元数据是否匹配
     * @param request 请求对象
     * @param consume Content-Type表达式
     */
    private void doVerifyWebRequestConsumeFilterMetadata(Request request, String consume) {
        String contentType = request.getHeader(HttpHeader.CONTENT_TYPE);
        if (StringUtils.isEmpty(contentType)) {
            throw new HttpMediaTypeNotSupportException("Http Request Media Type Missing.");
        } else if (!consume.equalsIgnoreCase(contentType)) {
            throw new HttpMediaTypeNotSupportException("Http Request Media Type["+ contentType +"] Not Support.");
        }
    }

    /**
     * 验证Accept元数据是否匹配
     * @param request 请求对象
     * @param produce Accept表达式
     */
    private void doVerifyWebRequestProduceFilterMetadata(Request request, String produce) {
        String accept = request.getHeader(HttpHeader.ACCEPT);
        if (StringUtils.isEmpty(accept)) {
            throw new HttpNotAcceptableException("Http Request Accept Missing.");
        }

        Set<String> mediaTypes = new HashSet<>();
        String[] acceptArray = accept.split(",");
        for (String acceptValue : acceptArray) {
            String[] weightAcceptArray = acceptValue.split(";");
            if (weightAcceptArray.length == 0) {
                continue;
            }
            mediaTypes.add(weightAcceptArray[0]);
        }
        if (!mediaTypes.contains(produce) && !mediaTypes.contains(HttpResponseBodyHandler.ANY_CONTENT_TYPE)) {
            throw new HttpNotAcceptableException("Http Request Accept["+ produce +"] Not Support.");
        }
    }
}
